home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / sound / ay8910.c < prev    next >
C/C++ Source or Header  |  2000-04-23  |  19KB  |  690 lines

  1. /***************************************************************************
  2.  
  3.   ay8910.c
  4.  
  5.  
  6.   Emulation of the AY-3-8910 / YM2149 sound chip.
  7.  
  8.   Based on various code snippets by Ville Hallik, Michael Cuddy,
  9.   Tatsuyuki Satoh, Fabrice Frances, Nicola Salmoria.
  10.  
  11. ***************************************************************************/
  12.  
  13. #include "driver.h"
  14. #include "ay8910.h"
  15.  
  16.  
  17. #define MAX_OUTPUT 0x7fff
  18.  
  19. #define STEP 0x8000
  20.  
  21.  
  22. struct AY8910
  23. {
  24.     int Channel;
  25.     int SampleRate;
  26.     mem_read_handler PortAread;
  27.     mem_read_handler PortBread;
  28.     mem_write_handler PortAwrite;
  29.     mem_write_handler PortBwrite;
  30.     int register_latch;
  31.     unsigned char Regs[16];
  32.     unsigned int UpdateStep;
  33.     int PeriodA,PeriodB,PeriodC,PeriodN,PeriodE;
  34.     int CountA,CountB,CountC,CountN,CountE;
  35.     unsigned int VolA,VolB,VolC,VolE;
  36.     unsigned char EnvelopeA,EnvelopeB,EnvelopeC;
  37.     unsigned char OutputA,OutputB,OutputC,OutputN;
  38.     signed char CountEnv;
  39.     unsigned char Hold,Alternate,Attack,Holding;
  40.     int RNG;
  41.     unsigned int VolTable[32];
  42. };
  43.  
  44. /* register id's */
  45. #define AY_AFINE    (0)
  46. #define AY_ACOARSE    (1)
  47. #define AY_BFINE    (2)
  48. #define AY_BCOARSE    (3)
  49. #define AY_CFINE    (4)
  50. #define AY_CCOARSE    (5)
  51. #define AY_NOISEPER    (6)
  52. #define AY_ENABLE    (7)
  53. #define AY_AVOL        (8)
  54. #define AY_BVOL        (9)
  55. #define AY_CVOL        (10)
  56. #define AY_EFINE    (11)
  57. #define AY_ECOARSE    (12)
  58. #define AY_ESHAPE    (13)
  59.  
  60. #define AY_PORTA    (14)
  61. #define AY_PORTB    (15)
  62.  
  63.  
  64. static struct AY8910 AYPSG[MAX_8910];        /* array of PSG's */
  65.  
  66.  
  67.  
  68. void _AYWriteReg(int n, int r, int v)
  69. {
  70.     struct AY8910 *PSG = &AYPSG[n];
  71.     int old;
  72.  
  73.  
  74.     PSG->Regs[r] = v;
  75.  
  76.     /* A note about the period of tones, noise and envelope: for speed reasons,*/
  77.     /* we count down from the period to 0, but careful studies of the chip     */
  78.     /* output prove that it instead counts up from 0 until the counter becomes */
  79.     /* greater or equal to the period. This is an important difference when the*/
  80.     /* program is rapidly changing the period to modulate the sound.           */
  81.     /* To compensate for the difference, when the period is changed we adjust  */
  82.     /* our internal counter.                                                   */
  83.     /* Also, note that period = 0 is the same as period = 1. This is mentioned */
  84.     /* in the YM2203 data sheets. However, this does NOT apply to the Envelope */
  85.     /* period. In that case, period = 0 is half as period = 1. */
  86.     switch( r )
  87.     {
  88.     case AY_AFINE:
  89.     case AY_ACOARSE:
  90.         PSG->Regs[AY_ACOARSE] &= 0x0f;
  91.         old = PSG->PeriodA;
  92.         PSG->PeriodA = (PSG->Regs[AY_AFINE] + 256 * PSG->Regs[AY_ACOARSE]) * PSG->UpdateStep;
  93.         if (PSG->PeriodA == 0) PSG->PeriodA = PSG->UpdateStep;
  94.         PSG->CountA += PSG->PeriodA - old;
  95.         if (PSG->CountA <= 0) PSG->CountA = 1;
  96.         break;
  97.     case AY_BFINE:
  98.     case AY_BCOARSE:
  99.         PSG->Regs[AY_BCOARSE] &= 0x0f;
  100.         old = PSG->PeriodB;
  101.         PSG->PeriodB = (PSG->Regs[AY_BFINE] + 256 * PSG->Regs[AY_BCOARSE]) * PSG->UpdateStep;
  102.         if (PSG->PeriodB == 0) PSG->PeriodB = PSG->UpdateStep;
  103.         PSG->CountB += PSG->PeriodB - old;
  104.         if (PSG->CountB <= 0) PSG->CountB = 1;
  105.         break;
  106.     case AY_CFINE:
  107.     case AY_CCOARSE:
  108.         PSG->Regs[AY_CCOARSE] &= 0x0f;
  109.         old = PSG->PeriodC;
  110.         PSG->PeriodC = (PSG->Regs[AY_CFINE] + 256 * PSG->Regs[AY_CCOARSE]) * PSG->UpdateStep;
  111.         if (PSG->PeriodC == 0) PSG->PeriodC = PSG->UpdateStep;
  112.         PSG->CountC += PSG->PeriodC - old;
  113.         if (PSG->CountC <= 0) PSG->CountC = 1;
  114.         break;
  115.     case AY_NOISEPER:
  116.         PSG->Regs[AY_NOISEPER] &= 0x1f;
  117.         old = PSG->PeriodN;
  118.         PSG->PeriodN = PSG->Regs[AY_NOISEPER] * PSG->UpdateStep;
  119.         if (PSG->PeriodN == 0) PSG->PeriodN = PSG->UpdateStep;
  120.         PSG->CountN += PSG->PeriodN - old;
  121.         if (PSG->CountN <= 0) PSG->CountN = 1;
  122.         break;
  123.     case AY_AVOL:
  124.         PSG->Regs[AY_AVOL] &= 0x1f;
  125.         PSG->EnvelopeA = PSG->Regs[AY_AVOL] & 0x10;
  126.         PSG->VolA = PSG->EnvelopeA ? PSG->VolE : PSG->VolTable[PSG->Regs[AY_AVOL] ? PSG->Regs[AY_AVOL]*2+1 : 0];
  127.         break;
  128.     case AY_BVOL:
  129.         PSG->Regs[AY_BVOL] &= 0x1f;
  130.         PSG->EnvelopeB = PSG->Regs[AY_BVOL] & 0x10;
  131.         PSG->VolB = PSG->EnvelopeB ? PSG->VolE : PSG->VolTable[PSG->Regs[AY_BVOL] ? PSG->Regs[AY_BVOL]*2+1 : 0];
  132.         break;
  133.     case AY_CVOL:
  134.         PSG->Regs[AY_CVOL] &= 0x1f;
  135.         PSG->EnvelopeC = PSG->Regs[AY_CVOL] & 0x10;
  136.         PSG->VolC = PSG->EnvelopeC ? PSG->VolE : PSG->VolTable[PSG->Regs[AY_CVOL] ? PSG->Regs[AY_CVOL]*2+1 : 0];
  137.         break;
  138.     case AY_EFINE:
  139.     case AY_ECOARSE:
  140.         old = PSG->PeriodE;
  141.         PSG->PeriodE = ((PSG->Regs[AY_EFINE] + 256 * PSG->Regs[AY_ECOARSE])) * PSG->UpdateStep;
  142.         if (PSG->PeriodE == 0) PSG->PeriodE = PSG->UpdateStep / 2;
  143.         PSG->CountE += PSG->PeriodE - old;
  144.         if (PSG->CountE <= 0) PSG->CountE = 1;
  145.         break;
  146.     case AY_ESHAPE:
  147.         /* envelope shapes:
  148.         C AtAlH
  149.         0 0 x x  \___
  150.  
  151.         0 1 x x  /___
  152.  
  153.         1 0 0 0  \\\\
  154.  
  155.         1 0 0 1  \___
  156.  
  157.         1 0 1 0  \/\/
  158.                   ___
  159.         1 0 1 1  \
  160.  
  161.         1 1 0 0  ////
  162.                   ___
  163.         1 1 0 1  /
  164.  
  165.         1 1 1 0  /\/\
  166.  
  167.         1 1 1 1  /___
  168.  
  169.         The envelope counter on the AY-3-8910 has 16 steps. On the YM2149 it
  170.         has twice the steps, happening twice as fast. Since the end result is
  171.         just a smoother curve, we always use the YM2149 behaviour.
  172.         */
  173.         PSG->Regs[AY_ESHAPE] &= 0x0f;
  174.         PSG->Attack = (PSG->Regs[AY_ESHAPE] & 0x04) ? 0x1f : 0x00;
  175.         if ((PSG->Regs[AY_ESHAPE] & 0x08) == 0)
  176.         {
  177.             /* if Continue = 0, map the shape to the equivalent one which has Continue = 1 */
  178.             PSG->Hold = 1;
  179.             PSG->Alternate = PSG->Attack;
  180.         }
  181.         else
  182.         {
  183.             PSG->Hold = PSG->Regs[AY_ESHAPE] & 0x01;
  184.             PSG->Alternate = PSG->Regs[AY_ESHAPE] & 0x02;
  185.         }
  186.         PSG->CountE = PSG->PeriodE;
  187.         PSG->CountEnv = 0x1f;
  188.         PSG->Holding = 0;
  189.         PSG->VolE = PSG->VolTable[PSG->CountEnv ^ PSG->Attack];
  190.         if (PSG->EnvelopeA) PSG->VolA = PSG->VolE;
  191.         if (PSG->EnvelopeB) PSG->VolB = PSG->VolE;
  192.         if (PSG->EnvelopeC) PSG->VolC = PSG->VolE;
  193.         break;
  194.     case AY_PORTA:
  195.         if ((PSG->Regs[AY_ENABLE] & 0x40) == 0)
  196. logerror("warning: write to 8910 #%d Port A set as input\n",n);
  197. if (PSG->PortAwrite) (*PSG->PortAwrite)(0,v);
  198. else logerror("PC %04x: warning - write %02x to 8910 #%d Port A\n",cpu_get_pc(),v,n);
  199.         break;
  200.     case AY_PORTB:
  201.         if ((PSG->Regs[AY_ENABLE] & 0x80) == 0)
  202. logerror("warning: write to 8910 #%d Port B set as input\n",n);
  203. if (PSG->PortBwrite) (*PSG->PortBwrite)(0,v);
  204. else logerror("PC %04x: warning - write %02x to 8910 #%d Port B\n",cpu_get_pc(),v,n);
  205.         break;
  206.     }
  207. }
  208.  
  209.  
  210. /* write a register on AY8910 chip number 'n' */
  211. void AYWriteReg(int chip, int r, int v)
  212. {
  213.     struct AY8910 *PSG = &AYPSG[chip];
  214.  
  215.  
  216.     if (r > 15) return;
  217.     if (r < 14)
  218.     {
  219.         if (r == AY_ESHAPE || PSG->Regs[r] != v)
  220.         {
  221.             /* update the output buffer before changing the register */
  222.             stream_update(PSG->Channel,0);
  223.         }
  224.     }
  225.  
  226.     _AYWriteReg(chip,r,v);
  227. }
  228.  
  229.  
  230.  
  231. unsigned char AYReadReg(int n, int r)
  232. {
  233.     struct AY8910 *PSG = &AYPSG[n];
  234.  
  235.  
  236.     if (r > 15) return 0;
  237.  
  238.     switch (r)
  239.     {
  240.     case AY_PORTA:
  241.         if ((PSG->Regs[AY_ENABLE] & 0x40) != 0)
  242. logerror("warning: read from 8910 #%d Port A set as output\n",n);
  243. if (PSG->PortAread) PSG->Regs[AY_PORTA] = (*PSG->PortAread)(0);
  244. else logerror("PC %04x: warning - read 8910 #%d Port A\n",cpu_get_pc(),n);
  245.         break;
  246.     case AY_PORTB:
  247.         if ((PSG->Regs[AY_ENABLE] & 0x80) != 0)
  248. logerror("warning: read from 8910 #%d Port B set as output\n",n);
  249. if (PSG->PortBread) PSG->Regs[AY_PORTB] = (*PSG->PortBread)(0);
  250. else logerror("PC %04x: warning - read 8910 #%d Port B\n",cpu_get_pc(),n);
  251.         break;
  252.     }
  253.     return PSG->Regs[r];
  254. }
  255.  
  256.  
  257. void AY8910Write(int chip,int a,int data)
  258. {
  259.     struct AY8910 *PSG = &AYPSG[chip];
  260.  
  261.     if (a & 1)
  262.     {    /* Data port */
  263.         AYWriteReg(chip,PSG->register_latch,data);
  264.     }
  265.     else
  266.     {    /* Register port */
  267.         PSG->register_latch = data & 0x0f;
  268.     }
  269. }
  270.  
  271. int AY8910Read(int chip)
  272. {
  273.     struct AY8910 *PSG = &AYPSG[chip];
  274.  
  275.     return AYReadReg(chip,PSG->register_latch);
  276. }
  277.  
  278.  
  279. /* AY8910 interface */
  280. READ_HANDLER( AY8910_read_port_0_r ) { return AY8910Read(0); }
  281. READ_HANDLER( AY8910_read_port_1_r ) { return AY8910Read(1); }
  282. READ_HANDLER( AY8910_read_port_2_r ) { return AY8910Read(2); }
  283. READ_HANDLER( AY8910_read_port_3_r ) { return AY8910Read(3); }
  284. READ_HANDLER( AY8910_read_port_4_r ) { return AY8910Read(4); }
  285.  
  286. WRITE_HANDLER( AY8910_control_port_0_w ) { AY8910Write(0,0,data); }
  287. WRITE_HANDLER( AY8910_control_port_1_w ) { AY8910Write(1,0,data); }
  288. WRITE_HANDLER( AY8910_control_port_2_w ) { AY8910Write(2,0,data); }
  289. WRITE_HANDLER( AY8910_control_port_3_w ) { AY8910Write(3,0,data); }
  290. WRITE_HANDLER( AY8910_control_port_4_w ) { AY8910Write(4,0,data); }
  291.  
  292. WRITE_HANDLER( AY8910_write_port_0_w ) { AY8910Write(0,1,data); }
  293. WRITE_HANDLER( AY8910_write_port_1_w ) { AY8910Write(1,1,data); }
  294. WRITE_HANDLER( AY8910_write_port_2_w ) { AY8910Write(2,1,data); }
  295. WRITE_HANDLER( AY8910_write_port_3_w ) { AY8910Write(3,1,data); }
  296. WRITE_HANDLER( AY8910_write_port_4_w ) { AY8910Write(4,1,data); }
  297.  
  298.  
  299.  
  300. static void AY8910Update(int chip,INT16 **buffer,int length)
  301. {
  302.     struct AY8910 *PSG = &AYPSG[chip];
  303.     INT16 *buf1,*buf2,*buf3;
  304.     int outn;
  305.  
  306.     buf1 = buffer[0];
  307.     buf2 = buffer[1];
  308.     buf3 = buffer[2];
  309.  
  310.  
  311.     /* The 8910 has three outputs, each output is the mix of one of the three */
  312.     /* tone generators and of the (single) noise generator. The two are mixed */
  313.     /* BEFORE going into the DAC. The formula to mix each channel is: */
  314.     /* (ToneOn | ToneDisable) & (NoiseOn | NoiseDisable). */
  315.     /* Note that this means that if both tone and noise are disabled, the output */
  316.     /* is 1, not 0, and can be modulated changing the volume. */
  317.  
  318.  
  319.     /* If the channels are disabled, set their output to 1, and increase the */
  320.     /* counter, if necessary, so they will not be inverted during this update. */
  321.     /* Setting the output to 1 is necessary because a disabled channel is locked */
  322.     /* into the ON state (see above); and it has no effect if the volume is 0. */
  323.     /* If the volume is 0, increase the counter, but don't touch the output. */
  324.     if (PSG->Regs[AY_ENABLE] & 0x01)
  325.     {
  326.         if (PSG->CountA <= length*STEP) PSG->CountA += length*STEP;
  327.         PSG->OutputA = 1;
  328.     }
  329.     else if (PSG->Regs[AY_AVOL] == 0)
  330.     {
  331.         /* note that I do count += length, NOT count = length + 1. You might think */
  332.         /* it's the same since the volume is 0, but doing the latter could cause */
  333.         /* interferencies when the program is rapidly modulating the volume. */
  334.         if (PSG->CountA <= length*STEP) PSG->CountA += length*STEP;
  335.     }
  336.     if (PSG->Regs[AY_ENABLE] & 0x02)
  337.     {
  338.         if (PSG->CountB <= length*STEP) PSG->CountB += length*STEP;
  339.         PSG->OutputB = 1;
  340.     }
  341.     else if (PSG->Regs[AY_BVOL] == 0)
  342.     {
  343.         if (PSG->CountB <= length*STEP) PSG->CountB += length*STEP;
  344.     }
  345.     if (PSG->Regs[AY_ENABLE] & 0x04)
  346.     {
  347.         if (PSG->CountC <= length*STEP) PSG->CountC += length*STEP;
  348.         PSG->OutputC = 1;
  349.     }
  350.     else if (PSG->Regs[AY_CVOL] == 0)
  351.     {
  352.         if (PSG->CountC <= length*STEP) PSG->CountC += length*STEP;
  353.     }
  354.  
  355.     /* for the noise channel we must not touch OutputN - it's also not necessary */
  356.     /* since we use outn. */
  357.     if ((PSG->Regs[AY_ENABLE] & 0x38) == 0x38)    /* all off */
  358.         if (PSG->CountN <= length*STEP) PSG->CountN += length*STEP;
  359.  
  360.     outn = (PSG->OutputN | PSG->Regs[AY_ENABLE]);
  361.  
  362.  
  363.     /* buffering loop */
  364.     while (length)
  365.     {
  366.         int vola,volb,volc;
  367.         int left;
  368.  
  369.  
  370.         /* vola, volb and volc keep track of how long each square wave stays */
  371.         /* in the 1 position during the sample period. */
  372.         vola = volb = volc = 0;
  373.  
  374.         left = STEP;
  375.         do
  376.         {
  377.             int nextevent;
  378.  
  379.  
  380.             if (PSG->CountN < left) nextevent = PSG->CountN;
  381.             else nextevent = left;
  382.  
  383.             if (outn & 0x08)
  384.             {
  385.                 if (PSG->OutputA) vola += PSG->CountA;
  386.                 PSG->CountA -= nextevent;
  387.                 /* PeriodA is the half period of the square wave. Here, in each */
  388.                 /* loop I add PeriodA twice, so that at the end of the loop the */
  389.                 /* square wave is in the same status (0 or 1) it was at the start. */
  390.                 /* vola is also incremented by PeriodA, since the wave has been 1 */
  391.                 /* exactly half of the time, regardless of the initial position. */
  392.                 /* If we exit the loop in the middle, OutputA has to be inverted */
  393.                 /* and vola incremented only if the exit status of the square */
  394.                 /* wave is 1. */
  395.                 while (PSG->CountA <= 0)
  396.                 {
  397.                     PSG->CountA += PSG->PeriodA;
  398.                     if (PSG->CountA > 0)
  399.                     {
  400.                         PSG->OutputA ^= 1;
  401.                         if (PSG->OutputA) vola += PSG->PeriodA;
  402.                         break;
  403.                     }
  404.                     PSG->CountA += PSG->PeriodA;
  405.                     vola += PSG->PeriodA;
  406.                 }
  407.                 if (PSG->OutputA) vola -= PSG->CountA;
  408.             }
  409.             else
  410.             {
  411.                 PSG->CountA -= nextevent;
  412.                 while (PSG->CountA <= 0)
  413.                 {
  414.                     PSG->CountA += PSG->PeriodA;
  415.                     if (PSG->CountA > 0)
  416.                     {
  417.                         PSG->OutputA ^= 1;
  418.                         break;
  419.                     }
  420.                     PSG->CountA += PSG->PeriodA;
  421.                 }
  422.             }
  423.  
  424.             if (outn & 0x10)
  425.             {
  426.                 if (PSG->OutputB) volb += PSG->CountB;
  427.                 PSG->CountB -= nextevent;
  428.                 while (PSG->CountB <= 0)
  429.                 {
  430.                     PSG->CountB += PSG->PeriodB;
  431.                     if (PSG->CountB > 0)
  432.                     {
  433.                         PSG->OutputB ^= 1;
  434.                         if (PSG->OutputB) volb += PSG->PeriodB;
  435.                         break;
  436.                     }
  437.                     PSG->CountB += PSG->PeriodB;
  438.                     volb += PSG->PeriodB;
  439.                 }
  440.                 if (PSG->OutputB) volb -= PSG->CountB;
  441.             }
  442.             else
  443.             {
  444.                 PSG->CountB -= nextevent;
  445.                 while (PSG->CountB <= 0)
  446.                 {
  447.                     PSG->CountB += PSG->PeriodB;
  448.                     if (PSG->CountB > 0)
  449.                     {
  450.                         PSG->OutputB ^= 1;
  451.                         break;
  452.                     }
  453.                     PSG->CountB += PSG->PeriodB;
  454.                 }
  455.             }
  456.  
  457.             if (outn & 0x20)
  458.             {
  459.                 if (PSG->OutputC) volc += PSG->CountC;
  460.                 PSG->CountC -= nextevent;
  461.                 while (PSG->CountC <= 0)
  462.                 {
  463.                     PSG->CountC += PSG->PeriodC;
  464.                     if (PSG->CountC > 0)
  465.                     {
  466.                         PSG->OutputC ^= 1;
  467.                         if (PSG->OutputC) volc += PSG->PeriodC;
  468.                         break;
  469.                     }
  470.                     PSG->CountC += PSG->PeriodC;
  471.                     volc += PSG->PeriodC;
  472.                 }
  473.                 if (PSG->OutputC) volc -= PSG->CountC;
  474.             }
  475.             else
  476.             {
  477.                 PSG->CountC -= nextevent;
  478.                 while (PSG->CountC <= 0)
  479.                 {
  480.                     PSG->CountC += PSG->PeriodC;
  481.                     if (PSG->CountC > 0)
  482.                     {
  483.                         PSG->OutputC ^= 1;
  484.                         break;
  485.                     }
  486.                     PSG->CountC += PSG->PeriodC;
  487.                 }
  488.             }
  489.  
  490.             PSG->CountN -= nextevent;
  491.             if (PSG->CountN <= 0)
  492.             {
  493.                 /* Is noise output going to change? */
  494.                 if ((PSG->RNG + 1) & 2)    /* (bit0^bit1)? */
  495.                 {
  496.                     PSG->OutputN = ~PSG->OutputN;
  497.                     outn = (PSG->OutputN | PSG->Regs[AY_ENABLE]);
  498.                 }
  499.  
  500.                 /* The Random Number Generator of the 8910 is a 17-bit shift */
  501.                 /* register. The input to the shift register is bit0 XOR bit2 */
  502.                 /* (bit0 is the output). */
  503.  
  504.                 /* The following is a fast way to compute bit 17 = bit0^bit2. */
  505.                 /* Instead of doing all the logic operations, we only check */
  506.                 /* bit 0, relying on the fact that after two shifts of the */
  507.                 /* register, what now is bit 2 will become bit 0, and will */
  508.                 /* invert, if necessary, bit 16, which previously was bit 18. */
  509.                 if (PSG->RNG & 1) PSG->RNG ^= 0x28000;
  510.                 PSG->RNG >>= 1;
  511.                 PSG->CountN += PSG->PeriodN;
  512.             }
  513.  
  514.             left -= nextevent;
  515.         } while (left > 0);
  516.  
  517.         /* update envelope */
  518.         if (PSG->Holding == 0)
  519.         {
  520.             PSG->CountE -= STEP;
  521.             if (PSG->CountE <= 0)
  522.             {
  523.                 do
  524.                 {
  525.                     PSG->CountEnv--;
  526.                     PSG->CountE += PSG->PeriodE;
  527.                 } while (PSG->CountE <= 0);
  528.  
  529.                 /* check envelope current position */
  530.                 if (PSG->CountEnv < 0)
  531.                 {
  532.                     if (PSG->Hold)
  533.                     {
  534.                         if (PSG->Alternate)
  535.                             PSG->Attack ^= 0x1f;
  536.                         PSG->Holding = 1;
  537.                         PSG->CountEnv = 0;
  538.                     }
  539.                     else
  540.                     {
  541.                         /* if CountEnv has looped an odd number of times (usually 1), */
  542.                         /* invert the output. */
  543.                         if (PSG->Alternate && (PSG->CountEnv & 0x20))
  544.                              PSG->Attack ^= 0x1f;
  545.  
  546.                         PSG->CountEnv &= 0x1f;
  547.                     }
  548.                 }
  549.  
  550.                 PSG->VolE = PSG->VolTable[PSG->CountEnv ^ PSG->Attack];
  551.                 /* reload volume */
  552.                 if (PSG->EnvelopeA) PSG->VolA = PSG->VolE;
  553.                 if (PSG->EnvelopeB) PSG->VolB = PSG->VolE;
  554.                 if (PSG->EnvelopeC) PSG->VolC = PSG->VolE;
  555.             }
  556.         }
  557.  
  558.         *(buf1++) = (vola * PSG->VolA) / STEP;
  559.         *(buf2++) = (volb * PSG->VolB) / STEP;
  560.         *(buf3++) = (volc * PSG->VolC) / STEP;
  561.  
  562.         length--;
  563.     }
  564. }
  565.  
  566.  
  567. void AY8910_set_clock(int chip,int clock)
  568. {
  569.     struct AY8910 *PSG = &AYPSG[chip];
  570.  
  571.     /* the step clock for the tone and noise generators is the chip clock    */
  572.     /* divided by 8; for the envelope generator of the AY-3-8910, it is half */
  573.     /* that much (clock/16), but the envelope of the YM2149 goes twice as    */
  574.     /* fast, therefore again clock/8.                                        */
  575.     /* Here we calculate the number of steps which happen during one sample  */
  576.     /* at the given sample rate. No. of events = sample rate / (clock/8).    */
  577.     /* STEP is a multiplier used to turn the fraction into a fixed point     */
  578.     /* number.                                                               */
  579.     PSG->UpdateStep = ((double)STEP * PSG->SampleRate * 8) / clock;
  580. }
  581.  
  582.  
  583. void AY8910_set_volume(int chip,int channel,int volume)
  584. {
  585.     struct AY8910 *PSG = &AYPSG[chip];
  586.     int ch;
  587.  
  588.     for (ch = 0; ch < 3; ch++)
  589.         if (channel == ch || channel == ALL_8910_CHANNELS)
  590.             mixer_set_volume(PSG->Channel + ch, volume);
  591. }
  592.  
  593.  
  594. static void build_mixer_table(int chip)
  595. {
  596.     struct AY8910 *PSG = &AYPSG[chip];
  597.     int i;
  598.     double out;
  599.  
  600.  
  601.     /* calculate the volume->voltage conversion table */
  602.     /* The AY-3-8910 has 16 levels, in a logarithmic scale (3dB per step) */
  603.     /* The YM2149 still has 16 levels for the tone generators, but 32 for */
  604.     /* the envelope generator (1.5dB per step). */
  605.     out = MAX_OUTPUT;
  606.     for (i = 31;i > 0;i--)
  607.     {
  608.         PSG->VolTable[i] = out + 0.5;    /* round to nearest */
  609.  
  610.         out /= 1.188502227;    /* = 10 ^ (1.5/20) = 1.5dB */
  611.     }
  612.     PSG->VolTable[0] = 0;
  613. }
  614.  
  615.  
  616.  
  617. void AY8910_reset(int chip)
  618. {
  619.     int i;
  620.     struct AY8910 *PSG = &AYPSG[chip];
  621.  
  622.  
  623.     PSG->register_latch = 0;
  624.     PSG->RNG = 1;
  625.     PSG->OutputA = 0;
  626.     PSG->OutputB = 0;
  627.     PSG->OutputC = 0;
  628.     PSG->OutputN = 0xff;
  629.     for (i = 0;i < AY_PORTA;i++)
  630.         _AYWriteReg(chip,i,0);    /* AYWriteReg() uses the timer system; we cannot */
  631.                                 /* call it at this time because the timer system */
  632.                                 /* has not been initialized. */
  633. }
  634.  
  635. static int AY8910_init(const struct MachineSound *msound,int chip,
  636.         int clock,int volume,int sample_rate,
  637.         mem_read_handler portAread,mem_read_handler portBread,
  638.         mem_write_handler portAwrite,mem_write_handler portBwrite)
  639. {
  640.     int i;
  641.     struct AY8910 *PSG = &AYPSG[chip];
  642.     char buf[3][40];
  643.     const char *name[3];
  644.     int vol[3];
  645.  
  646.  
  647.     memset(PSG,0,sizeof(struct AY8910));
  648.     PSG->SampleRate = sample_rate;
  649.     PSG->PortAread = portAread;
  650.     PSG->PortBread = portBread;
  651.     PSG->PortAwrite = portAwrite;
  652.     PSG->PortBwrite = portBwrite;
  653.     for (i = 0;i < 3;i++)
  654.     {
  655.         vol[i] = volume;
  656.         name[i] = buf[i];
  657.         sprintf(buf[i],"%s #%d Ch %c",sound_name(msound),chip,'A'+i);
  658.     }
  659.     PSG->Channel = stream_init_multi(3,name,vol,sample_rate,chip,AY8910Update);
  660.  
  661.     if (PSG->Channel == -1)
  662.         return 1;
  663.  
  664.     AY8910_set_clock(chip,clock);
  665.     AY8910_reset(chip);
  666.  
  667.     return 0;
  668. }
  669.  
  670.  
  671.  
  672. int AY8910_sh_start(const struct MachineSound *msound)
  673. {
  674.     int chip;
  675.     const struct AY8910interface *intf = msound->sound_interface;
  676.  
  677.  
  678.     for (chip = 0;chip < intf->num;chip++)
  679.     {
  680.         if (AY8910_init(msound,chip,intf->baseclock,
  681.                 intf->mixing_level[chip] & 0xffff,
  682.                 Machine->sample_rate,
  683.                 intf->portAread[chip],intf->portBread[chip],
  684.                 intf->portAwrite[chip],intf->portBwrite[chip]) != 0)
  685.             return 1;
  686.         build_mixer_table(chip);
  687.     }
  688.     return 0;
  689. }
  690.